/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.sourceforge.slcwsn.event;

import com.google.code.xbeejavaapi.api.XBee;
import net.sourceforge.slcwsn.network.Network;
import net.sourceforge.slcwsn.sensors.Sensor;
import net.sourceforge.slcwsn.sensors.SensorCreationException;
import net.sourceforge.slcwsn.sensors.SensorFactory;
import org.apache.log4j.Logger;

/**
 *
 * @author David Miguel Antunes <davidmiguel [ at ] antunes.net>
 */
public class EventFactory {

    private static final int MESG_TYPE_NODE_ALIVE = 0;
    private static final int MESG_TYPE_PIR_DETECTION = 1;
    private static final Logger logger = Logger.getLogger(EventFactory.class);
    private Network network;

    public EventFactory(Network network) {
        this.network = network;
    }

    public void parse(String in, long time, XBee xbee) throws ParsingException, SensorCreationException {
        logger.trace("Parsing string \"" + in + "\"");
        try {
            if (in.length() < 1) {
                throw new ParsingException("Data too short");
            }
            if (in.charAt(0) != '#') {
                throw new ParsingException("Wrong fist character");
            }
            in = in.substring(1, in.length());
            String[] fields = in.split("\\|");
            switch (Integer.parseInt(fields[0])) {
                case MESG_TYPE_NODE_ALIVE: {
                    int seqNum = Integer.parseInt(fields[1]);
                    int size = Integer.parseInt(fields[2]);
                    int sensorType = Integer.parseInt(fields[3]);
                    long sensorId = Long.parseLong(fields[4]);
                    long checksum = Long.parseLong(fields[5]);
                    long computedChecksum = (MESG_TYPE_NODE_ALIVE + seqNum + size + sensorType + sensorId) % 256;
                    if (checksum == computedChecksum) {
                        Sensor sensor = network.getSensors().get(sensorId);
                        if (sensor == null) {
                            sensor = new SensorFactory(network).createSensor(sensorType, sensorId);
                            SensorDiscoveredEvent sde = new SensorDiscoveredEvent(time, sensor, network);
                            network.newEvent(sde);
                        }
                        sensor.processSequenceNumber(seqNum, time);
                        SensorAliveEvent event = new SensorAliveEvent(time, sensor, network, sensor.getCurrentSeqNum());
                        SensorMessageEvent finalEvent = sensor.eventFactory(event, xbee);
                        if (event == finalEvent) {
                            network.newEvent(event);
                        }
                    } else {
                        logger.debug("Checksum check FAILED");
                    }
                }
                break;
                case MESG_TYPE_PIR_DETECTION: {
                    int seqNum = Integer.parseInt(fields[1]);
                    int size = Integer.parseInt(fields[2]);
                    long sensorId = Long.parseLong(fields[3]);
                    long checksum = Long.parseLong(fields[4]);
                    long computedChecksum = (MESG_TYPE_PIR_DETECTION + seqNum + size + sensorId) % 256;
                    if (checksum == computedChecksum) {
                        Sensor sensor = network.getSensors().get(sensorId);
                        if (sensor == null) {
                            throw new ParsingException("Unknown sensor with id=" + sensorId);
                        }
                        sensor.processSequenceNumber(seqNum, time);
                        SensorMessageEvent event = new PIRDetectionEvent(time, sensor, network, sensor.getCurrentSeqNum());
                        SensorMessageEvent finalEvent = sensor.eventFactory(event, xbee);
                        if (event == finalEvent) {
                            network.newEvent(event);
                        }
                    } else {
                        logger.debug("Checksum check FAILED");
                    }
                }
                break;
                default:
                    throw new ParsingException("Unknown message type");
            }
        } catch (Exception e) {
            logger.error(e + " - " + e.getStackTrace()[0]);
            throw new ParsingException("Exception while parsing event", e);
        }
    }
}
